﻿///////////////////////////////////////////////////////////////////////////////////////////////
//作者    ：陈国成
//创建时间：2009-10-16
//版本    ：1.0
//描述    ：电子试卷生成策略生成基类,如果用不同的算法，可以重载此类
//最后修改者：陈国成
//////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Entity;
using System.Linq.Expressions;
using Common;
using DAL;
using System.Data.Linq;
using System.Configuration;
using System.Xml.Linq;
namespace BAL
{


    public class XmlQuestionHelper
    {
        
        public static  XmlQuestion GetXmlQuestionInfo(string content)
        {
            XmlQuestion m_Question = new XmlQuestion();
            try
            {


                XDocument doc = XDocument.Parse(content);
                XElement root = doc.Root;

                #region 解析出题的类型
                if (root.Attribute("type") != null)
                {
                    m_Question.Type = root.Attribute("type").Value;
                }
                if (root.Attribute("allscore") != null)
                {
                    m_Question.AllScore = int.Parse(root.Attribute("allscore").Value);
                }
                if (root.Attribute("allcount") != null)
                {
                    m_Question.AllCount = int.Parse(root.Attribute("allcount").Value);
                }
                if (root.Attribute("startdate") != null)
                {
                    m_Question.StartDate = DateTime.Parse(root.Attribute("startdate").Value);
                }
                if (root.Attribute("enddate") != null)
                {
                    m_Question.EndDate = DateTime.Parse(root.Attribute("enddate").Value);
                }
                if (root.Attribute("appearnum") != null)
                {
                    m_Question.AppearNum = root.Attribute("appearnum").Value;
                }
                //AppearNum
                if (root.Attribute("singlescore") != null)
                {
                    m_Question.SingleScore = new List<decimal>();

                    string[] singleScores = root.Attribute("singlescore").Value.Split(' ');
                    foreach (string item in singleScores)
                    {
                        m_Question.SingleCondtion = m_Question.SingleCondtion + item + " ";
                        m_Question.SingleScore.Add(decimal.Parse(item));
                    }
                    if (m_Question.SingleCondtion != "")
                    {
                        m_Question.SingleCondtion = m_Question.SingleCondtion.Substring(0, m_Question.SingleCondtion.Length - 1);
                    }
                }
                if (root.Attribute("subjectid") != null)
                {
                    m_Question.SubjectId = root.Attribute("subjectid").Value;
                }
                if (root.Attribute("bookids") != null)
                {
                    string str = root.Attribute("bookids").Value;
                    if (str != "")
                    {
                        string[] arr = str.Split(',');
                        m_Question.BookIds = new List<string>();
                        foreach (var item in arr)
                        {
                            m_Question.BookIds.Add(item);
                        }
                    }
                }
                #endregion

                #region 解析新旧题比例
                //XElement questionRepeats = root.Element("latestquestionrepeats");
                //if (questionRepeats != null)
                //{
                //    var query = from item in questionRepeats.Elements("latestquestionrepeat")
                //                select item;
                //    if (query != null && query.Count() > 0)
                //    {
                //        m_Question.LatestQuestionRepeats = new List<XmlLatestQuestionRepeat>();
                //        foreach (var item in query)
                //        {
                //            XmlLatestQuestionRepeat rept = new XmlLatestQuestionRepeat();
                //            if (item.Attribute("latestquestionpercent") != null)
                //            {
                //                rept.LatestQuestionPercent = double.Parse(item.Attribute("latestquestionpercent").Value);
                //                int value = (int)Math.Floor(m_Question.AllCount * rept.LatestQuestionPercent);
                //                rept.LatestQuestionValue = value <= 0 ? 1 : value;
                //            }
                //            if (item.Attribute("optiontype") != null)
                //            {
                //                rept.OptionType = item.Attribute("optiontype").Value;
                //            }
                //            if (item.Attribute("optionvalue") != null)
                //            {
                //                rept.OptionTypeValue = DateTime.Parse(item.Attribute("optionvalue").Value);
                //            }
                //            latestQuestionRepeatCondtion = latestQuestionRepeatCondtion + " and ResourceElectron.CreateDate" + rept.OptionType + "'" + rept.OptionTypeValue + "' ";
                //            m_Question.LatestQuestionRepeats.Add(rept);
                //        }
                //        int diffrenceValue = m_Question.AllCount - m_Question.LatestQuestionRepeats.Sum(p => p.LatestQuestionValue);
                //        if (diffrenceValue != 0)
                //        {
                //            m_Question.LatestQuestionRepeats[m_Question.LatestQuestionRepeats.Count() - 1].LatestQuestionValue = m_Question.LatestQuestionRepeats[m_Question.LatestQuestionRepeats.Count() - 1].LatestQuestionValue + diffrenceValue;
                //        }
                //        latestQuestionRepeatCondtion = latestQuestionRepeatCondtion.Substring(0, latestQuestionRepeatCondtion.Length - 1);
                //    }
                //}
                #endregion

                #region 解析出难度系数集合
                XElement diffs = root.Element("diffs");
                if (diffs != null)
                {
                    var query = from item in diffs.Elements("diff")
                                select item;
                    if (query != null && query.Count() > 0)
                    {
                        m_Question.Diffs = new List<XmlDiff>();
                        foreach (var item in query)
                        {
                            XmlDiff diff = new XmlDiff();

                            if (item.Attribute("diffid") != null)
                            {
                                diff.DiffId = item.Attribute("diffid").Value;
                            }
                            if (item.Attribute("diffoptiontype") != null)
                            {
                                diff.DiffOptionType = item.Attribute("diffoptiontype").Value;
                            }
                            if (item.Attribute("difftypepercent") != null)
                            {
                                diff.DiffTypePercent = double.Parse(item.Attribute("difftypepercent").Value);
                                int value = (int)Math.Floor(m_Question.AllCount * diff.DiffTypePercent);
                                value = value <= 0 ? 1 : value;
                                int diffNum =m_Question.AllCount - m_Question.Diffs.Sum(p => p.DiffTypeValue);
                                if (value > diffNum) value = diffNum;
                                diff.DiffTypeValue = value;
                            }
                            m_Question.Diffs.Add(diff);
                        }
                        int diffrenceValue = m_Question.AllCount - m_Question.Diffs.Sum(p => p.DiffTypeValue);
                        if (diffrenceValue != 0)
                            m_Question.Diffs[m_Question.Diffs.Count() - 1].DiffTypeValue = m_Question.Diffs[m_Question.Diffs.Count() - 1].DiffTypeValue + diffrenceValue;
                    }
                }
                #endregion

                #region 解析知识点集合
                XElement knowpoints = root.Element("knowpoints");
                if (knowpoints != null)
                {
                    var query = from item in knowpoints.Elements("knowpoint")
                                select item;
                    if (query != null && query.Count() > 0)
                    {
                        m_Question.KnowPoints = new List<XmlKnowPoint>();
                        foreach (var item in query)
                        {
                            XmlKnowPoint point = new XmlKnowPoint();
                            if (item.Attribute("knowpointid") != null)
                            {
                                point.KnowPointId = item.Attribute("knowpointid").Value;
                            }

                            if (item.Attribute("knpointtypepercent") != null)
                            {
                                point.KnowPointTypePercent = double.Parse(item.Attribute("knpointtypepercent").Value);
                                int value = (int)Math.Floor(m_Question.AllCount * point.KnowPointTypePercent);
                                point.KnowPointTypeValue = value <= 0 ? 1 : value;
                                value = value <= 0 ? 1 : value;
                                int diffNum = m_Question.AllCount - m_Question.KnowPoints.Sum(p => p.KnowPointTypeValue);
                                if (value > diffNum) value = diffNum;
                                point.KnowPointTypeValue = value;
                            }
                            m_Question.KnowPoints.Add(point);
                        }
                        int diffrenceValue = m_Question.AllCount - m_Question.KnowPoints.Sum(p => p.KnowPointTypeValue);
                        if (diffrenceValue != 0)
                            m_Question.KnowPoints[m_Question.KnowPoints.Count() - 1].KnowPointTypeValue = m_Question.KnowPoints[m_Question.KnowPoints.Count() - 1].KnowPointTypeValue + diffrenceValue;
                    }
                }
                #endregion

                return m_Question;
            }
            catch (Exception ex)
            {
                //LogHelper.WriteLog(ex, "GetXmlQuestionInfo", new string[] { content });
                throw new Exception(ex.Message);
            }
        }


        public static string GetContent(XmlQuestion xmlQuestion)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
                sb.AppendLine("<question ");
                if (xmlQuestion.Type != null && xmlQuestion.Type != "")
                {
                    sb.Append(" type=\"" + xmlQuestion.Type + "\"");
                }
                if (xmlQuestion.SingleScore != null && xmlQuestion.SingleScore.Count() > 0)
                {
                    string singles = "";
                    foreach (int item in xmlQuestion.SingleScore)
                    {
                        singles = singles + item.ToString() + " ";
                    }
                    sb.Append(" singlescore=\"" + singles.Substring(0, singles.Length - 1) + "\"");
                }
                if (xmlQuestion.AllCount != 0)
                {
                    sb.Append(" allcount=\"" + xmlQuestion.AllCount.ToString() + "\"");
                }
                if (xmlQuestion.AllScore != 0)
                {
                    sb.Append(" allscore=\"" + xmlQuestion.AllScore.ToString() + "\"");
                }

                if (xmlQuestion.AppearNum != null && xmlQuestion.AppearNum != "")
                {
                    sb.Append(" appearnum=\"" + xmlQuestion.AppearNum + "\"");
                }

                if (xmlQuestion.StartDate != null)
                {
                    sb.Append(" startdate=\"" + xmlQuestion.StartDate.ToString() + "\"");
                }
                if (xmlQuestion.EndDate != null)
                {
                    sb.Append(" enddate=\"" + xmlQuestion.EndDate.ToString() + "\"");
                }

                if (xmlQuestion.SubjectId != null)
                {
                    sb.Append(" subjectid=\"" + xmlQuestion.SubjectId + "\"");
                }
                if (xmlQuestion.BookIds != null && xmlQuestion.BookIds.Count() > 0)
                {
                    string str = "";
                    foreach (var item in xmlQuestion.BookIds)
                    {
                        str = str + item + ",";
                    }
                    if (str != "")
                    {
                        str = str.Substring(0, str.Length - 1);
                    }

                    sb.Append(" bookids=\""+str+"\"");
                }

                sb.Append(" >");
                if (xmlQuestion.Diffs != null && xmlQuestion.Diffs.Count() > 0)
                {
                    sb.AppendLine("<diffs>");
                    foreach (XmlDiff diff in xmlQuestion.Diffs)
                    {
                        //&lt;   —   (<)     
                        //&gt;   —   (>) 
                        if (diff.DiffOptionType == ">")
                        {
                            diff.DiffOptionType = "&gt;";
                        }
                        else if (diff.DiffOptionType == ">=")
                        {
                            diff.DiffOptionType = "&gt;=";
                        }
                        else if (diff.DiffOptionType == "<=")
                        {
                            diff.DiffOptionType = "&lt;=";
                        }
                        else if (diff.DiffOptionType == "<")
                        {
                            diff.DiffOptionType = "&lt;";
                        }
                        sb.AppendLine("<diff   diffid=\"" + diff.DiffId + "\" diffoptiontype=\"" + diff.DiffOptionType + "\"  difftypepercent=\"" + diff.DiffTypePercent.ToString() + "\"></diff>");
                    }
                    sb.AppendLine("</diffs>");
                }
                if (xmlQuestion.KnowPoints != null && xmlQuestion.KnowPoints.Count() > 0)
                {
                    sb.AppendLine("<knowpoints>");
                    foreach (XmlKnowPoint point in xmlQuestion.KnowPoints)
                    {
                        sb.AppendLine("<knowpoint knowpointid=\"" + point.KnowPointId + "\" knpointtypepercent=\"" + point.KnowPointTypePercent.ToString() + "\"></knowpoint>");
                    }
                    sb.AppendLine("</knowpoints>");
                }
                //if (xmlQuestion.LatestQuestionRepeats != null && xmlQuestion.LatestQuestionRepeats.Count() > 0)
                //{
                //    sb.AppendLine("<latestquestionrepeats>");
                //    foreach (XmlLatestQuestionRepeat repeat in xmlQuestion.LatestQuestionRepeats)
                //    {
                //        sb.AppendLine("<latestquestionrepeat   latestquestionpercent=\""+repeat.LatestQuestionPercent.ToString()+"\" optiontype=\"=\" optionvalue=\""+repeat.OptionTypeValue.ToString()+"\"></latestquestionrepeat>");
                //    }
                //    sb.AppendLine("</latestquestionrepeats>");
                //}

                sb.AppendLine("</question>");

                return sb.ToString();
            }
            catch (Exception ex)
            {
                //LogHelper.WriteLog(ex, "GetContent");
                throw new Exception(ex.Message);
            }
        }
        
    }

   
    public abstract class BaseElectronTestPagerStratory 
    {
        private int m_SubjectId = 0;

        public int SubjectId
        {
            get { return m_SubjectId; }
            set { m_SubjectId = value; }
        }

        private XmlQuestion m_Question = new XmlQuestion();
        /// <summary>
        /// 随机组卷循环最少次数
        /// </summary>
        protected double CircleNumber = 150000;

        /// <summary>
        /// 保存过滤出的条件
        /// </summary>
        internal XmlQuestion QuestionInfo
        {
            get { return m_Question; }
        }

        protected BaseElectronTestPagerStratory()
        {
            if (ConfigurationManager.AppSettings["CircleNumber"] != null)
            {
                if (!double.TryParse(ConfigurationManager.AppSettings["CircleNumber"], out CircleNumber))
                {
                    CircleNumber = 100000;
                }
            }
        }
        public abstract IList<QuestionInfo> GenerateElectronTestPager(string content,IList<QuestionInfo> selectedQuestionInfos);

        /// <summary>
        /// 根据知识点Id集合，难度系数Id集合，新旧题比例集合，单题分值过滤出部分所要的记录
        /// </summary>
        /// <param name="content">xml格式的条件</param>
        /// <returns>Models.ResourceElectron>对象集合</returns>
        protected virtual List<Models.Question> PreGenerateElectronTestPager(string content, IList<QuestionInfo> selectedQuestionInfos)
        {
            List<Models.Question> resouce = new List<Models.Question>();
            m_Question = XmlQuestionHelper.GetXmlQuestionInfo(content);
            
            if (m_Question != null)
            {

                try
                {
                    using (var db=DatabaseHelper.GetDashboardData())
                    {

                        #region  从数据库中同步取出这些满足条件的记录
                        StringBuilder sql = new StringBuilder();
                        sql.AppendLine("SELECT Questions.Id,Title ,QuesTypeId ,Score ,Answer ,SubjectId ,GradeId,KnowId ,Questions.KeyWord ,StatusId ,Printer");
                        sql.AppendLine(",PrintDate ,UserId,DifficId ,LevelId  ,BookId   ,AssessId  ,CreateDate ,State,FinalReview");
                        sql.AppendLine(",Serial ,Counts ,Remark ,PrinterId ,SubKnow ,ComputeTime ,ROC ,CognitiveLevelId ,FirstReview ");
                        sql.AppendLine("FROM Questions ");

                        if (m_Question.Diffs != null && m_Question.Diffs.Count() > 0) //难度Id集合
                        {
                            sql.AppendLine(" , Diffic  where Questions.DifficId= Diffic.id   ");
                        }
                        else
                        {
                            sql.AppendLine("  where 1=1 and StatusId=5  ");
                        }


                        if (m_Question.StartDate != null && m_Question.EndDate != null && m_Question.AppearNum!=null  && m_Question.AppearNum!="" && m_Question.AppearNum!="")
                        {
                            sql.AppendLine("and Questions.Id not in (SELECT [QuestionId] FROM [QuestionsUseNumber] ");
                            sql.AppendLine("where [CreateDate]>='"+m_Question.StartDate.Value.ToString("yyyy-MM-dd HH:mm")+"' and  [CreateDate]<='"+m_Question.EndDate.Value.ToString("yyyy-MM-dd HH:mm")+"'");
                            sql.AppendLine("group by QuestionId having count(*)>="+m_Question.AppearNum+"  )" );
                        }

                        if (m_SubjectId > 0)
                        {
                            sql.AppendLine(" and SubjectId="+m_SubjectId.ToString());
                        }

                        if(m_Question.SubjectId!= null && m_Question.SubjectId!="" && m_Question.SubjectId!="0")
                        {
                            sql.AppendLine("  and SubjectId="+m_Question.SubjectId);
                            if(m_Question.BookIds!=null && m_Question.BookIds.Count>0)
                            {
                                string line = "";
                                foreach (string item in m_Question.BookIds)
                                {
                                    line = line + " ROC like '%" + item + "%' or";
                                }
                                if (line != "")
                                {
                                    line = line.Substring(0, line.Length - 2);
                                    line = " ( "+line+" ) ";
                                    sql.AppendLine("  and "+line);
                                }
                            }
                        }
                        if (m_Question.Type != null && m_Question.Type != "") //题型Id
                        {
                            sql.AppendLine(" and QuesTypeId=" + m_Question.Type + "");
                        }
                        if (m_Question.SingleScore != null && m_Question.SingleScore.Count() > 0) //还没有加好，少单题分数字段
                        {
                            string singles = "";
                            foreach (int item in m_Question.SingleScore)
                            {
                                singles = singles + item.ToString() + ",";
                            }
                            sql.AppendLine(" and Score in(" + singles.Substring(0, singles.Length - 1) + ")");
                        }
                        if (m_Question.KnowPoints != null && m_Question.KnowPoints.Count() > 0) //知识点
                        {
                            string pCondition = "";
                            for (int i = 0; i < m_Question.KnowPoints.Count(); i++)
                            {
                                pCondition = pCondition + "" + m_Question.KnowPoints[i].KnowPointId + ",";
                            }
                            sql.AppendLine(" and KnowId in( " + pCondition.Substring(0, pCondition.Length - 1) + " )");

                        }
   
                        if (m_Question.Diffs != null && m_Question.Diffs.Count() > 0) //难度Id集合
                        {
                            IList<int> ids = new List<int>();
                            foreach (XmlDiff diffItem in m_Question.Diffs)
                            {
                                ids.Add(int.Parse(diffItem.DiffId));
                            }
                            IList<DifficInfo> diffList = Diffic.GetDifficInfoByIds(ids);
                            string diffCondtion = "";
                            foreach (XmlDiff xmlDiffItem in m_Question.Diffs)
                            {
                                var quey = from item in diffList
                                           where item.Id.ToString() == xmlDiffItem.DiffId
                                           select item;
                                if (quey != null && quey.Count() > 0)
                                {
                                    foreach (var qItem in quey)
                                    {
                                        xmlDiffItem.Coneffic = int.Parse(qItem.Keyword.Trim());
                                        diffCondtion = diffCondtion + "Diffic.Keyword" + xmlDiffItem.DiffOptionType + qItem.Keyword + " or ";
                                    }
                                }
                            }
                            if (diffCondtion != "")
                            {
                                sql.AppendLine(" and  (" + diffCondtion.Substring(0, diffCondtion.Length - 3) + ")");
                            }
                        }

 
                        #endregion

                        if (selectedQuestionInfos != null && selectedQuestionInfos.Count() > 0)
                        {
                            IList<int> ids = selectedQuestionInfos.Select(p => p.Id).ToList<int>();
                            resouce = db.ExecuteQuery<Models.Question>(sql.ToString()).Where(p=> ! ids.Contains(p.Id)).ToList<Models.Question>();
                        }
                        else
                        {
                            resouce = db.ExecuteQuery<Models.Question>(sql.ToString()).ToList<Models.Question>();
                        }
                    }

                }
                catch (Exception ex)
                {
                    //LogHelper.WriteLog(ex, "PreGenerateElectronTestPager", new string[] { content });
                    throw new Exception(ex.Message);
                }
            }

            return resouce;

        }
    }
}
